﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Windows.Forms;
using System.Xml;


namespace Singbon.Utility {

    /// 配置类设计,从配制文件CollectConfigkq中取得工作站信息
    /// </summary>
    public class Config {
        public bool IsDebug = false;
        public bool bMark = false;//区别全量授权，还是增量授权
        public string ServerName;//数据库服务器
        public string DBName;//数据库名
        public string uid;//用户名
        public string pwd;//密码
        public string ConnectionStringLocal;
        public string Opcde;//在运行调试的时候这个存储的也是登陆名。
        public int savingLimitType;
        public decimal savingLimit;
        public int takeLimitType;
        public decimal takeLimit;
        public string dbType;//数据源类型 0直连 1webservice
        public string WebServiceURL;
        public int takeFarePwd = 0;

        //窗体
        public static Dictionary<Form, FormWindowState> OpenedFormList = new Dictionary<Form, FormWindowState>();

        public string username;//操作员真实姓名
        public string userdept;//操作员部门
        public string usercode;//操作员登录账号是的，
        public string userpwd;//操作员登录账号
        public int usertype;//操作员登录类型 1代表管理员，2代表普通操作员，3代表出纳员
        public string userCardNo;//出纳员登录卡号
        public int isuse;//是否充许自动统计 1表示可以自动统计，0不允许自动统计
        public DateTime AUTOSTATISTICSDT;//自动统计时间
        private static Config instance;

        /// CAN设备波特率
        /// </summary>
        public int BT = 40;//初始化为40K；CAN设备波特率

        /// can通讯类型  6:PCICAN,3:232CAN通讯 2:USBCAN通讯
        /// </summary>
        public int CANTYPE = 2;//6默认为PCI通讯，2USB

        ///默认1；代表服务不启动，0代表启动 
        /// </summary>
        public int checkflag = 1;//默认1；代表服务不启动，0代表启动

        /// 1活动，0死的
        /// </summary>
        public int islive = 1;//活动，0死的

        ///串口的通讯波特率 可设置,但软件重启后又变为9600 
        /// </summary>
        public int ComBT = 9600;//串口的通讯波特率，默认9600 19200 115200；三种模式

        ///采集类型 0代表所有(混合消费) 1代表消费 2代表考勤 3代表门禁考勤 可设置,但当软件重启后又变为0
        ///实际有作用,暂发发现不同类型与中心库交互不同,当为0时所有的都操作一遍
        /// </summary>
        public int CollectType = 0;


        ///读卡器串口
        /// </summary>
        public int CommtSet = 1;


        /// 采集连接服务器的连接字符串。在此系统中无用处
        /// </summary>
        public string ServerConnectionString = "";//

        ///采集本地库的连接字符串。 
        /// </summary>
        public string LocalConnectionString = "";//采集本地库的连接字符串。

        /// 工作站ID
        /// </summary>
        public int StationID = 0;//工作站ID

        /// 采集库所在电脑IP 暂时在系统中不起作用
        /// </summary>
        public string IP = "127.0.0.1";

        public string DataFilePath = @"D:\Data\";//数据文件路径
        public string LogFilePath = @"D:\log\";//日志文件路径
        public int LogFileDate = 60;
        public string RServerName = "";//服务器名称中心库
        public string RDataBase = "";//中心库数据库
        public string RUSerID = "";//中心库的用户名
        public string RPwd = "";//中心库的用户密码 
        public string LServerName = "";//服务器名称本地库
        public string LDataBase = "";//本地库数据库
        public string LUSerID = "";//本地库的用户名
        public string LPwd = "";//本地库的用户密码 L
        public string TestDay = "";
        public string DT = "";
        public string State = "0";
        public string usedday = "";
        public string softWareType = "";
        private string key = "singbone";
        public static string companyName;
        public static string companyNumber;
        public static string companyPass;
        public static int baseSector;

        public int Grant_State = 0;


        /// Web主机的地址
        /// </summary>
        public string eCardWebAddress;


        /// 系统空闲时间,可以发送全量黑名单
        /// </summary>
        public string FreeTime;
        private int terminalsPerGroup = 0;


        /// 增量警戒值，剩余空间小于该值之后需要发送全量
        /// </summary>
        public int IncBlacklistWarningValue = 600; //const ?
        /**************************************/
        public string SysPwd = "000";
        public string alsoOpenMonitor = "0";
        public string openSystemRestart = "0";
        /**************************************/
        /// 数据采集读取超时，单位毫秒
        /// </summary>
        public int RS485ReceiveTimeout = 10;
        //---------------------------------------------------------------
        public int BlackListUseDay = 20;//本地黑名单xml文件有效日期，默认20需要发送一次全量

#if DEBUG
        public int _onlyDebug = 0; //= 1;//仅仅调试，不使用数据库,2:调试
#else
        public int _onlyDebug = 0;
#endif

        public int OnlyDebug {
            get { return _onlyDebug; }
            set { _onlyDebug = value; }
        }

        public int SendHMDLimit = 1;//启用黑名单限制，1：手工全量发送时也控制，0不做控制 ，UDP通讯的时候不做控制。

        public int TerminalsPerGroup //黑名单发送时，每组终端个数。
        {
            get {
                return terminalsPerGroup;
            }
        }

        public int FrameWork3 = 1;// 是否启用.net 3环境，如果不启用就不能使用WCF监控


        /// 脱机警界值，以通讯错误计数
        /// </summary>
        public int OfflineCritical = 8;

        public Dictionary<string, List<string>> upgradeList = new Dictionary<string, List<string>>();
        public Dictionary<string, int> upgradeSizeList = new Dictionary<string, int>();
        static readonly object sync = new object();

        public Config() {

        }

        public static Config Instance {
            get {
                if (instance == null) {
                    lock (sync) {
                        if (instance == null) {
                            instance = new Config();
                        }
                    }
                }
                return instance;
            }
        }
        
        #region

        /// 得到日志文件的路径。
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public string LoadConfigDatePath(string name) {
            string sDataPath = null;
            string filepath = Config.Instance.GetConfigPath();
            XmlDocument doc = new XmlDocument();

            try {
                doc.Load(filepath + "\\" + name);
                XmlNodeList nodes = doc.SelectNodes("/configuration/appSettings/add");
                foreach (XmlNode node in nodes) {
                    switch (node.Attributes["key"].Value) {
                        case "DataFilePath":
                            sDataPath = node.Attributes["value"].Value.ToString();
                            break;
                        default:
                            break;
                    }
                }
            } catch (Exception ex) {
                return sDataPath = null;
            }
            return sDataPath;
        }

        /// 修改开放时间段。
        /// </summary>
        /// <param name="sFilePath"></param>
        /// <param name="sFileName"></param>
        /// <returns></returns>
        /// 
        public string LoadState_FS(string sFilePath, string sFileName) {

            string istate = null;
            try {
                using (FileStream FS = new FileStream(sFilePath + "\\" + sFileName + ".xml", FileMode.Open, FileAccess.Read, FileShare.Write)) {
                    StreamReader SR = new StreamReader(FS);
                    istate = SR.ReadLine();
                    SR.Dispose();
                    SR.Close();
                }
            } catch (Exception ex) {
                istate = "-1";
            }
            return istate;
        }

        public void UpState_FS(string sFilePath, string sFileName, int iType) {
            using (FileStream FS = new FileStream(sFilePath + "\\" + sFileName + ".xml", FileMode.Open, FileAccess.Write, FileShare.Read)) {
                StreamWriter SW = new StreamWriter(FS);
                if (iType == 1) {
                    SW.WriteLine("1");
                } else if (iType == 0) {
                    SW.WriteLine("0");
                } else if (iType == -3) {
                    SW.WriteLine("-3");
                }
                SW.Dispose();
                SW.Close();
            }
        }


        /// 修改时间段标记
        /// </summary>
        /// <param name="sFilePath"></param>
        /// <param name="sFileName"></param>
        /// <param name="sState"></param>
        /// <returns></returns>
        public bool UpdateState(string sFilePath, string sFileName, string sState) {
            XmlDocument doc = new XmlDocument();
            bool bMark = false;
            doc.Load(sFilePath + "\\" + sFileName + ".xml");
            XmlNodeList nodes = doc.SelectNodes("/Configuration/LoadIsate");
            foreach (XmlNode node in nodes) {
                if (node.Attributes["Value"].Value != null) {
                    node.Attributes["Value"].Value = sState;

                    bMark = true;
                    break;
                }
            }
            doc.Save(sFilePath + "\\" + sFileName + ".xml");
            return bMark;
        }
        public bool UpdateGroupTime(string sFilePath, string sFileName, string sCardno, string sGroupTime) {
            XmlDocument doc = new XmlDocument();
            bool bMark = false;
            try {
                doc.Load(sFilePath + "\\" + sFileName + ".xml");
                XmlNodeList nodes = doc.SelectNodes("/Configuration/GroupTime");
                foreach (XmlNode node in nodes) {
                    if (node.Attributes["Cardno"].Value == sCardno) {
                        node.Attributes["Value"].Value = sGroupTime;
                        bMark = true;
                        break;
                    }
                }
                if (!bMark)//添加新的结点
                {
                    XmlNode node2 = doc.SelectSingleNode("Configuration");
                    XmlElement xel = doc.CreateElement("GroupTime");
                    XmlAttribute key = doc.CreateAttribute("Cardno");
                    key.InnerText = sCardno;
                    xel.Attributes.Append(key);
                    XmlAttribute value = doc.CreateAttribute("Value");
                    value.InnerText = sGroupTime;
                    xel.Attributes.Append(value);
                    node2.AppendChild(xel);

                }
                doc.Save(sFilePath + "\\" + sFileName + ".xml");
            } catch (Exception ex) {
                return false;
            }
            return true;
        }

        /// 保存修改的人员时间段信息。
        /// </summary>
        /// <param name="sFilePath"></param>
        /// <param name="name">工作站ID号</param>
        /// <param name="sCardno"></param>
        /// <param name="iTermID">终端ID号</param>
        /// <param name="Grouptime"></param>
        /// <returns></returns>
        public bool SaveChangeGroupTime(string sFilePath, string name) {

            try {
                XmlDocument doc = new XmlDocument();
                XmlElement xel = doc.CreateElement("1");
                doc.AppendChild(xel);

                //XmlElement xel2 = doc.CreateElement("LoadIsate");
                ////XmlAttribute key = doc.CreateAttribute("GrantInfo");
                //////key.InnerText = sCardno;
                ////xel2.Attributes.Append(key);

                //XmlAttribute value = doc.CreateAttribute("Value");
                //value.InnerText = svalue;
                //xel2.Attributes.Append(value);
                //xel.AppendChild(xel2);

                doc.Save(sFilePath + "\\" + name + ".xml");
            } catch (Exception ex) {
                return false;
            }
            return true;
        }

        /// 检查指定的文件是否存在
        /// </summary>
        /// <param name="sFilePath"></param>
        /// <param name="sName"></param>
        /// <returns></returns>
        public bool JudgeFile_Grant(string sFilePath, string sName) {
            string sPath = sFilePath + "\\" + sName + ".xml";
            if (File.Exists(sPath)) {
                return true;
            } else {
                return false;
            }

        }

        #endregion

        /// 保存配置文件
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool SaveConfig() {
            //得到配置文件的路径
            string filepath = Config.Instance.GetConfigPath();
            XmlDocument doc = new XmlDocument();
            Config cfg = Config.Instance;
            try {
                doc.Load(filepath + "\\SingbonConfig.xml");//加载配置文件
                XmlNodeList nodes = doc.SelectNodes("/configuration/appSettings/add");//获取节点列表
                foreach (XmlNode node in nodes) {
                    switch (node.Attributes["key"].Value) {

                        case "CONN_STRING":
                            node.Attributes["value"].Value = cfg.LocalConnectionString;
                            break;
                        case "ServerConnStr":
                            node.Attributes["value"].Value = cfg.ServerConnectionString;
                            break;
                        case "StationID":
                            node.Attributes["value"].Value = cfg.StationID.ToString();
                            break;
                        case "IP":
                            node.Attributes["value"].Value = cfg.IP;
                            break;
                        case "LogFilePath":
                            node.Attributes["value"].Value = cfg.LogFilePath.ToString();
                            break;
                        case "DataFilePath":
                            node.Attributes["value"].Value = cfg.DataFilePath.ToString();
                            break;
                        case "LogFileDate":
                            node.Attributes["value"].Value = cfg.LogFileDate.ToString();
                            break;
                        case "BlakBlltWarningValue":
                            node.Attributes["value"].Value = cfg.IncBlacklistWarningValue.ToString();
                            break;
                        case "dbType":
                            node.Attributes["value"].Value = cfg.dbType;
                            break;
                        case "RServerName":
                            node.Attributes["value"].Value = cfg.RServerName;
                            break;
                        case "RDataBase":
                            node.Attributes["value"].Value = cfg.RDataBase;
                            break;
                        case "RUserID":
                            node.Attributes["value"].Value = cfg.RUSerID;
                            break;
                        case "RPwd":
                            node.Attributes["value"].Value = cfg.RPwd;
                            break;
                        case "LServerName":
                            node.Attributes["value"].Value = cfg.LServerName;
                            break;
                        case "LDataBase":
                            node.Attributes["value"].Value = cfg.LDataBase;
                            break;
                        case "LUserID":
                            node.Attributes["value"].Value = cfg.LUSerID;
                            break;
                        case "LPwd":
                            node.Attributes["value"].Value = cfg.LPwd;
                            break;
                        case "BT":
                            node.Attributes["value"].Value = cfg.BT.ToString();
                            break;
                        case "WebServiceURL":
                            node.Attributes["value"].Value = cfg.WebServiceURL;
                            break;
                        case "CANTYPE":
                            node.Attributes["value"].Value = cfg.CANTYPE.ToString();
                            break;
                        case "checkflag":
                            node.Attributes["value"].Value = cfg.checkflag.ToString();
                            break;
                        case "islive":
                            node.Attributes["value"].Value = cfg.islive.ToString();
                            break;
                        case "ComBT":
                            node.Attributes["value"].Value = cfg.ComBT.ToString();
                            break;
                        case "CollectType":
                            node.Attributes["value"].Value = cfg.CollectType.ToString();
                            break;
                        //读卡器串口
                        case "CommSet":
                            node.Attributes["value"].Value = cfg.CommtSet.ToString();
                            break;
                        case "SysPwd":
                            node.Attributes["value"].Value = cfg.SysPwd;
                            break;
                        case "alsoOpenMonitor":
                            node.Attributes["value"].Value = cfg.alsoOpenMonitor;
                            break;
                        case "openSystemRestart":
                            node.Attributes["value"].Value = cfg.openSystemRestart;
                            break;
                        default:
                            break;

                    }
                }

                doc.Save(filepath + "\\SingbonConfig.xml");
            } catch (Exception ex) {
                return false;
            }
            return true;
        }

        /// 加载station配置
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        public bool LoadConfig() {
            //得到配置文件的路径
            string filepath = GetConfigPath();

            XmlDocument doc = new XmlDocument();

            Config cfg = Config.Instance;
            try {
                doc.Load(filepath + "\\SingbonConfig.xml");//加载配置文件
                XmlNodeList nodes = doc.SelectNodes("/configuration/appSettings/add");//获取节点列表
                foreach (XmlNode node in nodes) {
                    switch (node.Attributes["key"].Value) {
                        case "dbType"://数据源类型
                            cfg.dbType = node.Attributes["value"].Value.ToString();
                            break;
                        case "CONN_STRING"://采集库连接字符串
                            cfg.LocalConnectionString = node.Attributes["value"].Value.ToString();
                            break;
                        case "ServerConnStr"://中心库连接字符串
                            cfg.ServerConnectionString = node.Attributes["value"].Value.ToString();
                            break;
                        case "WebServiceURL"://中心库连接字符串
                            cfg.WebServiceURL = node.Attributes["value"].Value.ToString();
                            break;
                        case "StationID"://工作站ID
                            cfg.StationID = Convert.ToInt32(node.Attributes["value"].Value);
                            break;

                        case "IP"://本机IP
                            cfg.IP = node.Attributes["value"].Value.ToString();

                            break;
                        case "LogFilePath"://日志文件路径
                            cfg.LogFilePath = node.Attributes["value"].Value.ToString();
                            break;
                        case "DataFilePath"://数据文件路径
                            cfg.DataFilePath = node.Attributes["value"].Value.ToString();
                            break;
                        case "LogFileDate"://日志保存时间
                            cfg.LogFileDate = Convert.ToInt32(node.Attributes["value"].Value.ToString());
                            break;
                        case "BlakBlltWarningValue"://增量黑名单警界值
                            cfg.IncBlacklistWarningValue = Convert.ToInt32(node.Attributes["value"].Value.ToString());
                            break;
                        case "RServerName": //中心库服务器(暂无用)
                            cfg.RServerName = node.Attributes["value"].Value.ToString();
                            break;
                        case "RDataBase"://中心库数据库名称(暂无用)
                            cfg.RDataBase = node.Attributes["value"].Value.ToString();

                            break;
                        case "RUserID"://中心库数据库登陆名(暂无用)
                            cfg.RUSerID = node.Attributes["value"].Value.ToString();
                            break;
                        case "RPwd"://中心库数据库登陆密码(暂无用)
                            cfg.RPwd = node.Attributes["value"].Value.ToString();
                            break;
                        case "LServerName"://采集库服务器名
                            cfg.LServerName = node.Attributes["value"].Value.ToString();
                            break;
                        case "LDataBase"://采集数据库文件名字
                            cfg.LDataBase = node.Attributes["value"].Value.ToString();
                            break;
                        case "LUserID"://采集库数据库系统登陆名
                            cfg.LUSerID = node.Attributes["value"].Value.ToString();
                            break;
                        case "LPwd"://采集库数据库系统登陆密码
                            cfg.LPwd = node.Attributes["value"].Value.ToString();
                            break;
                        case "BT"://CAN通信波特率
                            cfg.BT = Convert.ToInt32(node.Attributes["value"].Value.ToString());
                            break;
                        case "CANTYPE"://CAN类型
                            cfg.CANTYPE = Convert.ToInt32(node.Attributes["value"].Value.ToString());
                            break;
                        case "checkflag":////默认1；代表服务不启动，0代表启动/暂不知其真正用途
                            cfg.checkflag = Convert.ToInt32(node.Attributes["value"].Value.ToString());
                            break;
                        case "islive"://采集活动标记 //活动，0死的  /暂不知其真正用途
                            cfg.islive = Convert.ToInt32(node.Attributes["value"].Value.ToString());
                            break;
                        case "ComBT"://暂可设置,但无用,因未保存.软件重启后变为9600
                            cfg.ComBT = Convert.ToInt32(node.Attributes["value"].Value.ToString());
                            break;
                        case "CollectType"://采集类型无用为0 0代表所有 1代表消费 2代表考勤 3代表门禁考勤
                            cfg.CollectType = Convert.ToInt32(node.Attributes["value"].Value.ToString());
                            break;
                        case "CommSet"://读卡器串口
                            cfg.CommtSet = Convert.ToInt32(node.Attributes["value"].Value.ToString());
                            break;
                        case "SysPwd"://
                            cfg.SysPwd = node.Attributes["value"].Value.ToString();
                            break;
                        case "alsoOpenMonitor"://
                            cfg.alsoOpenMonitor = node.Attributes["value"].Value.ToString();
                            break;
                        case "openSystemRestart"://
                            cfg.openSystemRestart = node.Attributes["value"].Value.ToString();
                            break;
                        default:
                            break;
                    }
                }
            } catch (Exception ex) {

                string msg = ex.Message;
                return false;
            }
            return true;
        }


        /// 加载系统参数配置
        /// </summary>
        public void LoadSysParaConfig() {
            using (XmlTextReader xr = new XmlTextReader("SysParaConfig.xml")) {
                xr.Read();
                xr.ReadStartElement("CardInfo");
                companyName = xr.ReadElementString("CompanyName");
                companyNumber = xr.ReadElementString("CompanyNumber");
                companyPass = xr.ReadElementString("CompanyPass");
                baseSector = Convert.ToInt32(xr.ReadElementString("BaseSector"));
                xr.ReadEndElement();
            }
        }


        /// 保存系统参数配置
        /// </summary>
        public void SaveSysParaConfig() {
            using (XmlTextWriter xw = new XmlTextWriter("SysParaConfig.xml", null)) {
                xw.Formatting = Formatting.Indented;
                xw.WriteStartDocument();
                xw.WriteComment("Configuration of Card Information");
                xw.WriteStartElement("CardInfo");
                xw.WriteElementString("CompanyName", companyName);
                xw.WriteElementString("CompanyNumber", companyNumber);
                xw.WriteElementString("CompanyPass", companyPass);
                xw.WriteElementString("BaseSector", baseSector.ToString());
                xw.WriteEndElement();
                xw.WriteEndDocument();
                xw.Close();
            }
        }


        /// 获取配置文件所在路径
        /// </summary>
        /// <param name="filepath"></param>
        /// <returns></returns>
        public string GetConfigPath() {
            return Application.StartupPath;
            /**
             *  Process[] p = Process.GetProcessesByName("SingbonICCard");
            if (p.Length == 0)
            {
                p = Process.GetProcessesByName("SingbonICCard.vshost");
            }
            if (p.Length != 0)
            {
                return p[0].MainModule.FileName.Replace("SingbonICCard.vshost.exe", "").Replace("SingbonICCard.exe", "");
            }
            else
            {
                Application.Exit();
            }
            return null;
             * */
        }

        //字符串左补零
        public string StrLeftPad(string str, int num) {
            num = num - str.Length;
            for (int i = 0; i < num; i++) {
                str = "0" + str;
            }
            return str;
        }


        /// 加载升级文件
        /// </summary>
        /// <param name="filepath"></param>
        /// <returns></returns>
        public void LoadUpgradeFile() {
            try {
                upgradeList.Clear();
                upgradeSizeList.Clear();
                string filepath = GetConfigPath();
                string path = filepath + "\\upgrade\\";
                if (!Directory.Exists(path))
                    return;
                DirectoryInfo di = new DirectoryInfo(path);
                FileInfo[] files = di.GetFiles("*.hex");
                foreach (FileInfo f in files) {
                    List<string> upgradeStrs = new List<string>();
                    string str = "";
                    StreamReader sr = new StreamReader(f.FullName);
                    int size = 200;
                    string line = "";
                    while ((line = sr.ReadLine()) != null) {
                        if (line.StartsWith(":02")) {
                            continue;
                        }
                        str += line.Substring(9, line.Length - 11);
                    }
                    sr.Close();

                    int count = str.Length / 2;
                    count %= size;
                    count %= 4;
                    if (count > 0) {
                        count = 4 - count;
                        str += StrLeftPad("", count * 2);
                    }
                    int len = str.Length / 2 / size;
                    for (int i = 0; i < len; i++) {
                        upgradeStrs.Add(str.Substring(i * 2 * size, 2 * size));
                    }
                    if (str.Length % (2 * size) > 0) {
                        upgradeStrs.Add(str.Substring(len * 2 * size));
                    }
                    string name = f.Name.Substring(0, 1);
                    upgradeList.Add(name, upgradeStrs);
                    upgradeSizeList.Add(name, str.Length / 2);
                }
            } catch (Exception e) {

            }
        }


        /// 检查并设置窗体状态
        /// </summary>
        /// <param name="checkForm"></param>
        public void CheckAndSetFormState(Form checkForm) {
            bool exists = false;//是否已打开
            Form oldForm = new Form();//已存在的窗体
            FormWindowState oldState = FormWindowState.Normal;//原先窗体的状态

            foreach (Form f in OpenedFormList.Keys) {
                if (f.Text == checkForm.Text) {
                    exists = true;
                    oldForm = f;
                    oldState = OpenedFormList[f];
                }
            }

            if (exists) {
                oldForm.WindowState = oldState;
                oldForm.Activate();
            } else {
                checkForm.FormClosing += new FormClosingEventHandler(Form_FormClosing);
                OpenedFormList.Add(checkForm, checkForm.WindowState);
                checkForm.Show();
            }
        }


        /// 释放已打开的窗体
        /// </summary>
        public void DisposeOpenedForms() {
            Form monitorForm = null;
            foreach (Form f in OpenedFormList.Keys) {
                if (f.Text.Contains("监控")) {
                    monitorForm = f;
                    continue;
                }

                if (!f.IsDisposed) {
                    f.Dispose();
                }
            }
            if (monitorForm != null) {
                monitorForm.Close();
                monitorForm.Dispose();
            }
        }

        private void Form_FormClosing(object sender, FormClosingEventArgs e) {
            Form f = sender as Form;
            if (OpenedFormList.Keys.Contains(f)) {
                OpenedFormList.Remove(f);
            }
        }
    }
}